package log

import (
	"fmt"
	"gitee.com/KotlinToGo/xorm/ictx"
)

// LogContext 代表日志上下文
type LoggerCtx ictx.CtxHook

// SQLLogger represents an interface to log SQL
type ISQLLogger interface {
	BeforeSQL(context LoggerCtx) // only invoked when IsShowSQL is true
	AfterSQL(context LoggerCtx)  // only invoked when IsShowSQL is true
}

// ContextLogger 通过上下文返回一个 Logger接口
type IContextLogger interface {
	ISQLLogger
	DebugF(format string, v ...interface{})
	ErrorF(format string, v ...interface{})
	InfoF(format string, v ...interface{})
	WarnF(format string, v ...interface{})

	Level() LoggerLevel
	SetLevel(l LoggerLevel)

	ShowSQL(show ...bool)
	IsShowSQL() bool
}

var (
	_ IContextLogger = &LoggerAdapter{}
)

// enumerate all the ictx keys
var (
	SessionIDKey      = "__xorm_session_id"
	SessionKey        = "__xorm_session_key"
	SessionShowSQLKey = "__xorm_show_sql"
)

// LoggerAdapter wraps a Logger interface as LoggerContext interface
type LoggerAdapter struct {
	logger ILogger
}

// NewLoggerAdapter creates an adapter for old xorm logger interface
func NewLoggerAdapter(logger ILogger) IContextLogger {
	return &LoggerAdapter{
		logger: logger,
	}
}

// BeforeSQL implements ContextLogger
func (l *LoggerAdapter) BeforeSQL(ctx LoggerCtx) {}

// AfterSQL implements ContextLogger
func (l *LoggerAdapter) AfterSQL(ctx LoggerCtx) {
	var sessionPart string
	v := ctx.Ctx.Value(SessionIDKey)
	if key, ok := v.(string); ok {
		sessionPart = fmt.Sprintf(" [%s]", key)
	}
	if ctx.ExecuteTime > 0 {
		l.logger.InfoF("[SQL]%s %s %v - %v", sessionPart, ctx.SQL, ctx.Args, ctx.ExecuteTime)
	} else {
		l.logger.InfoF("[SQL]%s %s %v", sessionPart, ctx.SQL, ctx.Args)
	}
}

// DebugF implements ContextLogger
func (l *LoggerAdapter) DebugF(format string, v ...interface{}) {
	l.logger.DebugF(format, v...)
}

// ErrorF implements ContextLogger
func (l *LoggerAdapter) ErrorF(format string, v ...interface{}) {
	l.logger.ErrorF(format, v...)
}

// InfoF implements ContextLogger
func (l *LoggerAdapter) InfoF(format string, v ...interface{}) {
	l.logger.InfoF(format, v...)
}

// WarnF implements ContextLogger
func (l *LoggerAdapter) WarnF(format string, v ...interface{}) {
	l.logger.WarnF(format, v...)
}

// Level implements ContextLogger
func (l *LoggerAdapter) Level() LoggerLevel {
	return l.logger.Level()
}

// SetLevel implements ContextLogger
func (l *LoggerAdapter) SetLevel(lv LoggerLevel) {
	l.logger.SetLevel(lv)
}

// ShowSQL implements ContextLogger
func (l *LoggerAdapter) ShowSQL(show ...bool) {
	l.logger.ShowSQL(show...)
}

// IsShowSQL implements ContextLogger
func (l *LoggerAdapter) IsShowSQL() bool {
	return l.logger.IsShowSQL()
}
